﻿namespace ApiTemplate.Common
{
    public class EncryptionHelper
    {
        #region AES

        const string aesKey = "aesKey";

        /// <summary>
        /// AES加密
        /// </summary>
        /// <param name="text">加密文本</param>
        /// <returns></returns>
        public static string AESEncrypt(string text)
        {
            var encryptKey = Encoding.UTF8.GetBytes(aesKey);

            using var aesAlg = Aes.Create();
            using var encryptor = aesAlg.CreateEncryptor(encryptKey, aesAlg.IV);
            using var msEncrypt = new MemoryStream();
            using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write, true))

            using (var swEncrypt = new StreamWriter(csEncrypt, leaveOpen: true))
            {
                swEncrypt.Write(text);
            }

            var iv = aesAlg.IV;
            var dataLength = iv.Length + (int)msEncrypt.Length;
            var decryptedContent = msEncrypt.GetBuffer();
            var base64Length = Base64.GetMaxEncodedToUtf8Length(dataLength);
            var result = new byte[base64Length];

            Unsafe.CopyBlock(ref result[0], ref iv[0], (uint)iv.Length);
            Unsafe.CopyBlock(ref result[iv.Length], ref decryptedContent[0], (uint)msEncrypt.Length);

            Base64.EncodeToUtf8InPlace(result, dataLength, out base64Length);

            return Encoding.ASCII.GetString(result.AsSpan()[..base64Length]);
        }

        /// <summary>
        /// AES解密
        /// </summary>
        /// <param name="hash">加密后字符串</param>
        /// <returns></returns>
        public static string AESDecrypt(string hash)
        {
            var fullCipher = Convert.FromBase64String(hash);

            var iv = new byte[16];
            var cipher = new byte[fullCipher.Length - iv.Length];

            Unsafe.CopyBlock(ref iv[0], ref fullCipher[0], (uint)iv.Length);
            Unsafe.CopyBlock(ref cipher[0], ref fullCipher[iv.Length], (uint)(fullCipher.Length - iv.Length));
            var decryptKey = Encoding.UTF8.GetBytes(aesKey);

            using var aesAlg = Aes.Create();
            using var decryptor = aesAlg.CreateDecryptor(decryptKey, iv);
            using var msDecrypt = new MemoryStream(cipher);
            using var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read);
            using var srDecrypt = new StreamReader(csDecrypt);
            return srDecrypt.ReadToEnd();
        }
        #endregion

        #region Base64

        /// <summary>
        /// 将字符串转换为Base64
        /// </summary>
        /// <param name="str">需要转换的字符串</param>
        /// <returns>转换后的字符串</returns>
        public static string Base64Encrypt(string str)
        {
            //返回转后后的字符串
            return Convert.ToBase64String(Encoding.Default.GetBytes(str)).Replace("+", "%2b");
        }

        /// <summary>
        /// 将Base64解码为字符串
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static string Base64Decrypt(string str)
        {
            return Encoding.Default.GetString(Convert.FromBase64String(str.ToString())).Replace("%2b", "+");
        }
        #endregion

        #region Des加密
        /// <summary>
        /// 加密
        /// </summary>
        /// <param name="text">加密文本</param>
        /// <returns></returns>
        public static string DesEncrypt(string text)
        {
            using var des = DES.Create();
            byte[] inputByteArray;
            inputByteArray = Encoding.Default.GetBytes(text);

            des.Key = Encoding.ASCII.GetBytes("key$1234");
            des.IV = Encoding.ASCII.GetBytes("pwd$1234");

            using var ms = new MemoryStream();
            using var cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write);

            cs.Write(inputByteArray, 0, inputByteArray.Length);
            cs.FlushFinalBlock();

            StringBuilder ret = new();
            foreach (var b in ms.ToArray())
            {
                ret.AppendFormat("{0:X2}", b);
            }

            return ret.ToString();
        }

        /// <summary>
        /// 解密
        /// </summary>
        /// <param name="hash">加密后字符串</param>
        /// <returns></returns>
        public static string DesDecrypt(string hash)
        {
            using var des = DES.Create();
            int len;
            len = hash.Length / 2;
            var inputByteArray = new byte[len];
            int x, i;

            for (x = 0; x < len; x++)
            {
                i = Convert.ToInt32(hash.Substring(x * 2, 2), 16);
                inputByteArray[x] = (byte)i;
            }
            des.Key = Encoding.ASCII.GetBytes("key$1234");
            des.IV = Encoding.ASCII.GetBytes("pwd$1234");

            using var ms = new MemoryStream();
            using var cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write);

            cs.Write(inputByteArray, 0, inputByteArray.Length);
            cs.FlushFinalBlock();

            return Encoding.Default.GetString(ms.ToArray());
        }
        #endregion

        #region MD5
        /// <summary>
        /// 获取加密后的MD5值
        /// </summary>
        /// <param name="str">要操作的字符串</param>
        /// <returns>加密后的值</returns>
        public static string Md5(string str)
        {
            MD5 md5 = MD5.Create();
            byte[] inputBytes = Encoding.ASCII.GetBytes(str);
            byte[] hashBytes = md5.ComputeHash(inputBytes);
            StringBuilder sb = new();
            for (int i = 0; i < hashBytes.Length; i++)
            {
                sb.Append(hashBytes[i].ToString("x2"));
            }
            return sb.ToString();
        }
        #endregion
    }
}
